package com.kw.sqlsession;

import com.kw.config.BoundSQl;
import com.kw.pojo.Configuration;
import com.kw.pojo.MappedStatement;
import com.kw.util.GenericTokenParser;
import com.kw.util.ParameterMapping;
import com.kw.util.ParameterMappingTokenHandler;
import com.kw.util.TokenHandler;


import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Medivh on 2020/5/8.
 * 愿我出走半生,归来仍是少年
 */
public class SimpleExecutor implements Executor{


    @Override
    public <T> T query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, IntrospectionException, InstantiationException, InvocationTargetException {

        //1.注册驱动 获取链接
        Connection connection = configuration.getDataSource().getConnection();

        String sql = mappedStatement.getSql();
        //2获取sql 和参数
        BoundSQl boundSQl =  getBundSql(sql);


        //3获取预处理对象 prepareStatement
        PreparedStatement preparedStatement = connection.prepareCall(boundSQl.getSqlText());


        //4设置参数
        String paramterType = mappedStatement.getParamterType();


        Class<?> paramterClass = getClassType(paramterType);

        List<ParameterMapping> parameterMappingList = boundSQl.getParameterMappingList();
        for(int i =0;i<parameterMappingList.size();i++){
            String content =  parameterMappingList.get(i).getContent();
            //使用反射
            Field declaredField = paramterClass.getDeclaredField(content);
            //允许暴力访问
            declaredField.setAccessible(true);
            Object o = declaredField.get(params[0]);
            preparedStatement.setObject(i+1,o);

        }
        //5 执行参数
       ResultSet resultSet = preparedStatement.executeQuery();
       String resultType = mappedStatement.getResultType();
       Class<?> classType = getClassType(resultType);
        List<Object> list = new ArrayList<>();

       while (resultSet.next()){
           Object reusltObjecct = classType.newInstance();
           ResultSetMetaData metaData = resultSet.getMetaData();
           for(int i=1;i<=metaData.getColumnCount();i++){
               //字段名
           String columName = metaData.getColumnName(i);
             //字段值
           Object value = resultSet.getObject(columName);
             //反射
           PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columName, classType);

           Method writeMethod = propertyDescriptor.getWriteMethod();
           writeMethod.invoke(reusltObjecct,value);
           }
           list.add(reusltObjecct);
       }


        //6 封装返回结果集
        return (T) list;
    }

    private Class<?> getClassType(String paramterType) throws ClassNotFoundException {
        if(paramterType!=null){
           return  Class.forName(paramterType);
        }else{
            return null;
        }

    }

    private BoundSQl getBundSql(String sql) {
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{","}",parameterMappingTokenHandler);
        //解析出来的sql
        String parseSQl = genericTokenParser.parse(sql);
        //解析出来的参数名称
        List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
        BoundSQl boundSQl = new BoundSQl(parseSQl,parameterMappings);
        return boundSQl;
    }
}
